﻿
#include "ModbusRtuLink.h"
#include <QApplication>
#include <QDebug>
#include <string>
ModbusRtuLink::ModbusRtuLink(const QString & port_name,
                             int baud_,int data_bits ,
                             int stop_bits ,int parity_,QObject * parent)
    : LinkInterface{parent,Modbus}
{
    baud(baud_);
    dataBits(data_bits);
    stopBits(stop_bits);
    parity(parity_);
    portName(port_name);
}
//-----------------------------------------------------------------------------
bool ModbusRtuLink::connect()
{
    if (port_) {
        port_->disconnectDevice();
        for (unsigned i = 0; i < 3; i++) {
            QThread::usleep(1000);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
        }
        port_->deleteLater();
        port_ = nullptr;
    }
    port_  = new QModbusRtuSerialMaster(this);
    port_->setConnectionParameter(QModbusDevice::SerialPortNameParameter, _portName);
    port_->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, _baud);
    port_->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, static_cast<QSerialPort::DataBits>(_dataBits));
    port_->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, static_cast<QSerialPort::StopBits>(_stopBits));
    port_->setConnectionParameter(QModbusDevice::SerialParityParameter,   static_cast<QSerialPort::Parity>(_parity));
    port_->setTimeout(100);
    port_->setNumberOfRetries(0);
    if(!(port_->connectDevice())){
        port_->disconnectDevice();
        port_->deleteLater();
        isConnected_ = false;
        port_ = nullptr;
        return false;
    }
    isConnected_ = true;
    emit connectedChanged(isConnected_);
    return true;
}
//--------------------------------------------------------------------------
void  ModbusRtuLink::disConnect()
{
    isConnected_ = false;
    if (port_) {
        port_->disconnectDevice();
        port_->deleteLater();
        port_ = nullptr;
    }
    emit connectedChanged(isConnected_);
}
//----------------------------------------------------------------------------
bool  ModbusRtuLink::isConnected()
{
    if(port_){
        return (port_->state()==QModbusDevice::ConnectedState);
    }
    return  false;
}
//----------------------------------------------------------------------------------------
void ModbusRtuLink::writeUnit(QModbusDataUnit::RegisterType type ,int  serverAddress,int startAddress,QVector<quint16>values)
{
    if(! this->isConnected()){
        return;
    }
    mutex_.lock();
    QModbusDataUnit writeUnit = QModbusDataUnit(type,startAddress, values.size());
    for(int i=0; i<values.size(); i++){
        writeUnit.setValue(i, values.at(i));
    }
    if (auto *reply = port_->sendWriteRequest(writeUnit, serverAddress)) {
        if (!reply->isFinished()) {
            QObject::connect(reply, &QModbusReply::finished, this, [&,startAddress]() {
                emit writeUnitFinished();
                auto reply = qobject_cast<QModbusReply *>(sender());
                if (!reply) {
                    return;
                }
                if (reply->error() == QModbusDevice::NoError) {
                    const QModbusDataUnit unit = reply->result();
                    if(unit.valueCount()) {
                        emit writeData(reply->serverAddress(),startAddress,unit);
                    }
                }
                reply->deleteLater();
            });
        } else {
            reply->deleteLater();
        }
    }
    mutex_.unlock();
}
//-------------------------------------------------------------------------------------
void ModbusRtuLink::readUnit(QModbusDataUnit::RegisterType type,int  serverAddress, int startAddress,int readNum)
{
    if(! this->isConnected()){
        return;
    }
    mutex_.lock();
    if (auto *reply = port_->sendReadRequest(QModbusDataUnit(type, startAddress, readNum),  serverAddress)) {
        if (!reply->isFinished()){
            QObject::connect(reply, &QModbusReply::finished, this, [&,startAddress](){
                emit readUnitFinished();
                auto reply = qobject_cast<QModbusReply *>(sender());
                if (!reply) {
                    return;
                }
                if (reply->error() == QModbusDevice::NoError) {
                    const QModbusDataUnit unit = reply->result();
                    if(unit.valueCount()) {
                        emit readData(reply->serverAddress(),startAddress,unit);
                    }
                }
                reply->deleteLater();
            });
        }
        else{
            delete reply;
        }
    }
    mutex_.unlock();
}
//---------------------------------------------------------------------------------------------









